﻿using System;

namespace OverStore.Runtime.ObjectRepository.DeferredLoader
{
    /// <summary>
    /// Allows object to support deffered loading.
    /// </summary>
    public interface IDeferredLoadingSupport
    {
        /// <summary>
        /// Event that should be raised when object requires content loading.
        /// </summary>
        /// <remarks>
        /// Usually, object implements <see cref="IDeferredLoadingSupport"/> interface should
        /// raise <see cref="IDeferredLoadingSupport.LoadingRequired"/> event before any access to
        /// its data. 
        /// </remarks>
        /// <example>
        /// <code>
        /// /// {summary}
        /// /// This class supports deffered loading. It defines 
        /// /// method GetValue{T} that loads object before any 
        /// /// result will be get; and SetValue{T} that loads object 
        /// /// before any result will be set. 
        /// /// 
        /// /// Note that access to object identifier (if exists in object data) should not 
        /// /// causes loading, object identifier should be implemented as normal property.
        /// /// {/summary}
        /// public class BusinessObject : IDefferedLoadingSupport
        /// {
        ///     public event EventHandler LoadingRequired;
        /// 
        ///     /// {summary}
        ///     /// Object identifier should not be loaded defferly, it is always known before loading.
        ///     /// {/summary}
        ///     public int Id { get; set; }
        /// 
        ///     private string _Name;
        /// 
        ///     /// {summary}
        ///     /// Access to underlying field using GetValue and SetValue methods.
        ///     /// {/summary}
        ///     public string Name
        ///     {
        ///         get { return GetValue(() => _Name); }
        ///         set { SetValue(v => _Name = v, result); }
        ///     }
        /// 
        /// 
        ///     private GetDateTime _Birthdate;
        /// 
        ///     public GetDateTime BirthDate
        ///     {
        ///         get { return GetValue(() => _Birthdate); }
        ///         set { SetValue(v => _Birthdate = v, result); }
        ///     }
        /// 
        ///     // Using function instead of result for always access actual field result.
        ///     // Otherwise if LoadingRequired(this, EventArgs.Empty) causes object data reloading,
        ///     // method still has old copy of result in argument.
        ///     private T GetValue{T}(Func{T} getValue)
        ///     {
        ///         if (LoadingRequired != null)
        ///             LoadingRequired(this, EventArgs.Empty);
        ///         return getValue();
        ///     }
        /// 
        ///     private void SetValue{T}(Action{T} setValue, T result)
        ///     {
        ///         if (LoadingRequired != null)
        ///             LoadingRequired(this, EventArgs.Empty);
        ///         setValue(result);
        ///     }
        /// }
        /// </code>
        /// </example>
        event EventHandler LoadingRequired;
    }
}